#include "singlescatlayer.h"
#include <QTimer>
#include <QDebug>
#include <QtConcurrentRun>
#include <math.h>

SingleScatLayer::SingleScatLayer(QString layerName, QObject *parent) :
    AtmosLayer(layerName, 0, 0, parent)
{

}

void SingleScatLayer::recvSolar(double intensity, double zenith, double azimuth)
{
	qDebug() << "SingleScatLayer::recvSolar().";
	AtmosLayer::recvSolar(intensity, zenith, azimuth);

	//top layer need not wait  "emitLightDown" signal
	//it starts caculate when it recieve solar light
	QTimer::singleShot(10, this, SLOT(downInResponse()));
//	downInResponse();
}

#include <QtConcurrentRun>
void SingleScatLayer::downInResponse()
{
	m_loopDownTime++;

	qDebug() << m_layerName << "calculating upward incident light's response for the " << m_loopDownTime << "times.";

	//no downward scatter light at the most top layer
	//only downward solar incident light
	solarScatCaculate();

	//caculate downward irridiance, sendout getDownIrridiance() signal
	//must caculate here before emitLight()(downLight will be clear)
	downIrradianceCaculate();

	//now, save down light
	emitLight();

	//now, save up light
	m_currentDir = UP;
	emitLight();

	//exit when up/down light caculate/save over.
	exit(0);

	return;
}

void SingleScatLayer::solarScatCaculate()
{
    qDebug() << "SingleScatLayer::solarScatCaculate().";
    if(m_solarIntensity != 0){
	QFuture<void> solarUp = QtConcurrent::run(
		    this,
		    &SingleScatLayer::solarUpScatCaculate);
	QFuture<void> solarDown = QtConcurrent::run(
		    this,
		    &SingleScatLayer::solarDownScatCaculate);

	solarUp.waitForFinished();
	solarDown.waitForFinished();

	//caculate damped solar flux that will incident to next layer
	m_solarOut = m_solarIntensity *
		exp(-1*m_tau/qAbs(cos(m_solarZen)));

	m_solarIntensity = 0;

    }

}

void SingleScatLayer::solarUpScatCaculate()
{
    if(m_solarIntensity == 0)
	return;

    int iThetaS, iPhiS;
    double muI, muS;
    double singlePathCoeff;

    muI = qAbs(Cos(m_solarZen));
    singlePathCoeff = 0;

    for(iThetaS = 0; iThetaS < N_ZENITH; iThetaS++){

	muS = Cos(iThetaS*M_PI/N_PI + ANGLE_STEP/2);

	singlePathCoeff = (muI * (1-exp(-1*(1/muI+1/muS)*m_tau)))/(muI + muS);

	for(iPhiS = 0; iPhiS < 2*N_PI; iPhiS++){

	    linearPolar coeff;

	    solarScatCoeff(iThetaS, iPhiS, &coeff);

	    m_lightScatUp[iThetaS][iPhiS][I] +=
		    singlePathCoeff *
		    coeff.i ;

	    m_lightScatUp[iThetaS][iPhiS][Q] +=
		    singlePathCoeff*
		    coeff.q ;

	    m_lightScatUp[iThetaS][iPhiS][U] +=
		    singlePathCoeff*
		    coeff.u ;


	}
    }
}

void SingleScatLayer::solarDownScatCaculate()
{
    if(m_solarIntensity == 0)
	return;

    int iThetaS, iPhiS;
    double muI, muS;
    double singlePathCoeff;

    muI = qAbs(Cos(m_solarZen));
    singlePathCoeff = 0;

    for(iThetaS = 0; iThetaS > -N_ZENITH; iThetaS--){

	muS = qAbs(Cos(M_PI + iThetaS*M_PI/N_PI -ANGLE_STEP/2));

	singlePathCoeff = (muI * (exp(-1*m_tau/muI) - exp(-1*m_tau/muS))) / (muI - muS);

	for(iPhiS = 0; iPhiS < 2*N_PI; iPhiS++){

	    linearPolar coeff;

	    solarScatCoeff(iThetaS, iPhiS, &coeff);

	    m_lightScatD[-iThetaS][iPhiS][I] +=
		    singlePathCoeff*
		    coeff.i ;

	    m_lightScatD[-iThetaS][iPhiS][Q] +=
		    singlePathCoeff*
		    coeff.q ;

	    m_lightScatD[-iThetaS][iPhiS][U] +=
		    singlePathCoeff*
		    coeff.u ;

	}
    }
}
void SingleScatLayer::solarScatCoeff(int iThetaS, int iPhiS,
				     linearPolar *lightOut)
{
    lightOut->i = m_solarIntensity/4;
    lightOut->q = 0;
    lightOut->u = 0;
}
